module pflanza.plants;

import pflanza.lsystem;
import pflanza.polygen;
import std.stream;
import std.string;
import std.stdio;
import utils.configfile;
import utils.randval;
import utils.mover3;
import utils.vector3;

struct Plant {
    char[] pclass;
    char[] lsystem;
    RandVali variations;
    char[][int] materials;
    Polygen pgen;

    private {
        LSystemParser lsparser;
    }

    public static Plant opCall(ConfigNode pNode) {
        Plant ret;
        ret.pclass = pNode.getStringValue("class","default");
        ret.variations = RandVali(pNode.getStringValue("variations","1"));

        foreach (char[] id, char[] value; pNode.getSubNode("materials",true)) {
            ret.materials[atoi(id)] = value;
        }

        char[] filename = pNode.getStringValue("lsystemfile","");
        auto ruleFile = new File(filename, FileMode.In);
        ret.lsparser = new LSystemParser();
        ret.pgen = new Polygen(ret.lsparser);
        ret.lsparser.setRules(ruleFile);

        return ret;
    }
}

class Plants {
    private {
        Plant[char[]] mPlants;
    }

    public void fromNode(ConfigNode plantsNode) {
        foreach (char[] id, ConfigNode n; plantsNode) {
            try {
                Plant p = Plant(n);
                mPlants[id] = p;
            } catch (Exception e) {
                writefln("Plant %s failed to load: %s",id,e.msg);
            }
        }
    }

    public char[] variationName(char[] baseName, int varIdx) {
        return baseName ~ "_var" ~ std.string.toString(varIdx);
    }

    public void generate(char[] outputDir) {
        Mover3f up = Mover3f(Vector3f(0,0,0),Vector3f(0,1,0),Vector3f(1,0,0));
        foreach (char[] id, inout Plant p; mPlants) {
            for (int i = 0; i < p.variations.value; i++) {
                char[] filename = outputDir ~ variationName(id,i) ~ ".raw";
                p.pgen.execute(up,1);
                p.pgen.save(filename);
                writefln("Generated \"%s\", variation %d",id,i);
            }
        }
    }

    //write object definitions for plant variations to script
    public void writeScript(Stream st, char[] outputDir) {
        st.writefln("# Plants, object definitions");
        foreach (char[] id, inout Plant p; mPlants) {
            for (int i = 0; i < p.variations.value; i++) {
                char[] objId = variationName(id,i);
                char[] filename = outputDir ~ objId ~ ".raw";
                st.writefln("objtri %s %s",objId,filename);
                foreach (int matIndex, char[] matName; p.materials) {
                    st.writefln("assignmat %s %d",matName,matIndex);
                }
            }
        }
        st.writefln();
    }

    public Plant[char[]] plants() {
        return mPlants;
    }
}
